import CONSTANT from "../constant";
import Quat from "./quat";
import Vec3 from "./vec3";

export default class Mat3 {
    constructor(e00=1,e01=0,e02=0,e10=0,e11=1,e12=0,e20=0,e21=0,e22=1) {
        this.elements=new Float64Array(9);
        this.elements[0]=e00;
        this.elements[1]=e01;
        this.elements[2]=e02;
        this.elements[3]=e10;
        this.elements[4]=e11;
        this.elements[5]=e12;
        this.elements[6]=e20;
        this.elements[7]=e21;
        this.elements[8]=e22;
        CONSTANT.MAT3_NUM_CREATIONS++;
    }
    get e00(){
        return this.elements[0];
    }
    set e00(n){
        this.elements[0]=n;
    }
    get e01(){
        return this.elements[1];
    }
    set e01(n){
        this.elements[1]=n;
    }
    get e02(){
        return this.elements[2];
    }
    set e02(n){
        this.elements[2]=n;
    }
    get e10(){
        return this.elements[3];
    }
    set e10(n){
        this.elements[3]=n;
    }
    get e11(){
        return this.elements[4];
    }
    set e11(n){
        this.elements[4]=n;
    }
    get e12(){
        return this.elements[5];
    }
    set e12(n){
        this.elements[5]=n;
    }
    get e20(){
        return this.elements[6];
    }
    set e20(n){
        this.elements[6]=n;
    }
    get e21(){
        return this.elements[7];
    }
    set e21(n){
        this.elements[7]=n;
    }
    get e22(){
        return this.elements[8];
    }
    set e22(n){
        this.elements[8]=n;
    }
    fromQuat(_q) {
        let q=_q.elements;
        let x = q[0], y = q[1], z = q[2], w = q[3];
        let x2 = 2 * x;
        let y2 = 2 * y;
        let z2 = 2 * z;
        let xx = x * x2;
        let yy = y * y2;
        let zz = z * z2;
        let xy = x * y2;
        let yz = y * z2;
        let xz = x * z2;
        let wx = w * x2;
        let wy = w * y2;
        let wz = w * z2;
        let es=this.elements;
        es[0] = 1 - yy - zz;
        es[1] = xy - wz;
        es[2] = xz + wy;
        es[3] = xy + wz;
        es[4] = 1 - xx - zz;
        es[5] = yz - wx;
        es[6] = xz - wy;
        es[7] = yz + wx;
        es[8] = 1 - xx - yy;
        return this;
    }


    init(e00,e01,e02,e10,e11,e12,e20,e21,e22) {
        this.elements[0] = e00;
        this.elements[1] = e01;
        this.elements[2] = e02;
        this.elements[3] = e10;
        this.elements[4] = e11;
        this.elements[5] = e12;
        this.elements[6] = e20;
        this.elements[7] = e21;
        this.elements[8] = e22;
        return this;
    }
    identity() {
        this.elements[0] = 1;
        this.elements[1] = 0;
        this.elements[2] = 0;
        this.elements[3] = 0;
        this.elements[4] = 1;
        this.elements[5] = 0;
        this.elements[6] = 0;
        this.elements[7] = 0;
        this.elements[8] = 1;
        return this;
    }
    add(m) {
        return new Mat3(this.elements[0] + m.e00,this.elements[1] + m.e01,this.elements[2] + m.e02,this.elements[3] + m.e10,this.elements[4] + m.e11,this.elements[5] + m.e12,this.elements[6] + m.e20,this.elements[7] + m.e21,this.elements[8] + m.e22);
    }
    sub(m) {
        return new Mat3(this.elements[0] - m.e00,this.elements[1] - m.e01,this.elements[2] - m.e02,this.elements[3] - m.e10,this.elements[4] - m.e11,this.elements[5] - m.e12,this.elements[6] - m.e20,this.elements[7] - m.e21,this.elements[8] - m.e22);
    }
    scale(s) {
        return new Mat3(this.elements[0] * s,this.elements[1] * s,this.elements[2] * s,this.elements[3] * s,this.elements[4] * s,this.elements[5] * s,this.elements[6] * s,this.elements[7] * s,this.elements[8] * s);
    }
    mul(m) {
        return new Mat3(this.elements[0] * m.e00 + this.elements[1] * m.e10 + this.elements[2] * m.e20,this.elements[0] * m.e01 + this.elements[1] * m.e11 + this.elements[2] * m.e21,this.elements[0] * m.e02 + this.elements[1] * m.e12 + this.elements[2] * m.e22,this.elements[3] * m.e00 + this.elements[4] * m.e10 + this.elements[5] * m.e20,this.elements[3] * m.e01 + this.elements[4] * m.e11 + this.elements[5] * m.e21,this.elements[3] * m.e02 + this.elements[4] * m.e12 + this.elements[5] * m.e22,this.elements[6] * m.e00 + this.elements[7] * m.e10 + this.elements[8] * m.e20,this.elements[6] * m.e01 + this.elements[7] * m.e11 + this.elements[8] * m.e21,this.elements[6] * m.e02 + this.elements[7] * m.e12 + this.elements[8] * m.e22);
    }
    transpose() {
        return new Mat3(this.elements[0],this.elements[3],this.elements[6],this.elements[1],this.elements[4],this.elements[7],this.elements[2],this.elements[5],this.elements[8]);
    }
    determinant() {
        return this.elements[0] * (this.elements[4] * this.elements[8] - this.elements[5] * this.elements[7]) - this.elements[1] * (this.elements[3] * this.elements[8] - this.elements[5] * this.elements[6]) + this.elements[2] * (this.elements[3] * this.elements[7] - this.elements[4] * this.elements[6]);
    }
    trace() {
        return this.elements[0] + this.elements[4] + this.elements[8];
    }
    inverse() {
        let d00 = this.elements[4] * this.elements[8] - this.elements[5] * this.elements[7];
        let d01 = this.elements[3] * this.elements[8] - this.elements[5] * this.elements[6];
        let d02 = this.elements[3] * this.elements[7] - this.elements[4] * this.elements[6];
        let invDet = this.elements[0] * d00 - this.elements[1] * d01 + this.elements[2] * d02;
        if(invDet !== 0) {
            invDet = 1 / invDet;
        }
        return new Mat3(d00 * invDet,-(this.elements[1] * this.elements[8] - this.elements[2] * this.elements[7]) * invDet,(this.elements[1] * this.elements[5] - this.elements[2] * this.elements[4]) * invDet,-d01 * invDet,(this.elements[0] * this.elements[8] - this.elements[2] * this.elements[6]) * invDet,-(this.elements[0] * this.elements[5] - this.elements[2] * this.elements[3]) * invDet,d02 * invDet,-(this.elements[0] * this.elements[7] - this.elements[1] * this.elements[6]) * invDet,(this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3]) * invDet);
    }
    toArray(columnMajor) {
        if(columnMajor == null) {
            columnMajor = false;
        }
        if(columnMajor) {
            return [this.elements[0],this.elements[3],this.elements[6],this.elements[1],this.elements[4],this.elements[7],this.elements[2],this.elements[5],this.elements[8]];
        } else {
            return [this.elements[0],this.elements[1],this.elements[2],this.elements[3],this.elements[4],this.elements[5],this.elements[6],this.elements[7],this.elements[8]];
        }
    }
    clone() {
        return new Mat3(this.elements[0],this.elements[1],this.elements[2],this.elements[3],this.elements[4],this.elements[5],this.elements[6],this.elements[7],this.elements[8]);
    }
    toString() {
        return "Mat3[" + (this.elements[0] > 0 ? (this.elements[0] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[0] * 10000000 - 0.5 | 0) / 10000000) + ", " + (this.elements[1] > 0 ? (this.elements[1] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[1] * 10000000 - 0.5 | 0) / 10000000) + ", " + (this.elements[2] > 0 ? (this.elements[2] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[2] * 10000000 - 0.5 | 0) / 10000000) + ",\n" + "     " + (this.elements[3] > 0 ? (this.elements[3] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[3] * 10000000 - 0.5 | 0) / 10000000) + ", " + (this.elements[4] > 0 ? (this.elements[4] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[4] * 10000000 - 0.5 | 0) / 10000000) + ", " + (this.elements[5] > 0 ? (this.elements[5] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[5] * 10000000 - 0.5 | 0) / 10000000) + ",\n" + "     " + (this.elements[6] > 0 ? (this.elements[6] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[6] * 10000000 - 0.5 | 0) / 10000000) + ", " + (this.elements[7] > 0 ? (this.elements[7] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[7] * 10000000 - 0.5 | 0) / 10000000) + ", " + (this.elements[8] > 0 ? (this.elements[8] * 10000000 + 0.5 | 0) / 10000000 : (this.elements[8] * 10000000 - 0.5 | 0) / 10000000) + "]";
    }
}